/**
 * C2-01: STM32F401CC
 * 	1. LED		PC13		低电平点亮
 * 	2. UART		PA9 PA10
 * 	3. I2C		PB8 PB9
 * A1-01: AT24C02
 * 	1. SCL		PB8
 * 	2. SDA		PB9
 * 	3. WP		PB0
 *
 * 设备地址需要观察主板上 A0 A1 A2 三个地址配置引脚上的电阻是接 GND 还是 VCC
 *    A2 A1 A0	7bit-device-address
 * 0.  0  0  0	0x50
 * 1.  0  0  0	0x51
 * 2.  0  0  0	0x52
 * 3.  0  0  0	0x53
 * 4.  0  0  0	0x54
 * 5.  0  0  0	0x55
 * 6.  0  0  0	0x56
 * 7.  0  0  0	0x57
 */

#include <stdint.h>
#include "stm32f4xx_hal.h"
#include "bus/swi2c.h"
#include "bus/swi2c_ex.h"

#ifndef OUTPUT
#define OUTPUT 0
#endif

#ifndef INPUT
#define INPUT 1
#endif

void delay_us(int us);

extern uint32_t SystemCoreClock;
UART_HandleTypeDef huart1;
swi2c_t swi2c;

void HAL_MspInit(void)
{
	__HAL_RCC_SYSCFG_CLK_ENABLE();
	__HAL_RCC_PWR_CLK_ENABLE();
}

void _board_error_handler(void)
{
	__disable_irq();
	while (1) {
	}
}

void _board_clock_init(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
	RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

	__HAL_RCC_PWR_CLK_ENABLE();
	__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
	RCC_OscInitStruct.HSEState = RCC_HSE_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
	RCC_OscInitStruct.PLL.PLLM = 12;
	RCC_OscInitStruct.PLL.PLLN = 168;
	RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
	RCC_OscInitStruct.PLL.PLLQ = 4;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
		_board_error_handler();
	}

	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
	    | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
		_board_error_handler();
	}
}

void _board_uart_init()
{
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };

	/* UART CLK ENABLE */
	__HAL_RCC_USART1_CLK_ENABLE();

	/* UART IOREMAP */
	__HAL_RCC_GPIOA_CLK_ENABLE();
	GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	/* UART CONFIG */
	huart1.Instance = USART1;
	huart1.Init.BaudRate = 115200;
	huart1.Init.WordLength = UART_WORDLENGTH_8B;
	huart1.Init.StopBits = UART_STOPBITS_1;
	huart1.Init.Parity = UART_PARITY_NONE;
	huart1.Init.Mode = UART_MODE_TX_RX;
	huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	huart1.Init.OverSampling = UART_OVERSAMPLING_16;
	if (HAL_UART_Init(&huart1) != HAL_OK) {
		_board_error_handler();
	}
}

void _scl_set_val(int val)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, val);
}

void _sda_set_dir(int dir)
{
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };

	if (INPUT == dir) {
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	} else {
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	}

	GPIO_InitStruct.Pin = GPIO_PIN_9;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void _sda_set_val(int val)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, val);
}

int _sda_get_val()
{
	return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9);
}

void _board_swi2c_init()
{
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };

	/* EEPROM GPIO */
	__HAL_RCC_GPIOB_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	swi2c.cfg.fix.speed = 100000;
	swi2c.ops.usleep = delay_us;
	swi2c.ops.scl_set_val = _scl_set_val;
	swi2c.ops.sda_set_dir = _sda_set_dir;
	swi2c.ops.sda_set_val = _sda_set_val;
	swi2c.ops.sda_get_val = _sda_get_val;
}

int __io_putchar(int ch)
{
	HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
	return (ch);
}

int board_i2c_read(uint8_t device_address, uint8_t* memory_address, uint8_t* buffer, uint32_t length)
{
	return i2c_r8v8_read(&swi2c, device_address, memory_address, buffer, length);
}

int board_i2c_write(uint8_t device_address, uint8_t* memory_address, uint8_t* buffer, uint32_t length)
{
	return i2c_r8v8_write(&swi2c, device_address, memory_address, buffer, length);
}

void delay_us(int us)
{
	int curr_systick_timer_val = 0;     /* 当前滴答定时器的计数值 */
	int curr_systick_interrupt_cnt = 0; /* 当前滴答定时器中断计数值 */
	int delay_us_timer_cnt = 0;         /* 延时 us(参数) 时间对应的滴答定时器计数值 */
	int timeout_systick_timer_val = 0;  /* 延时结束时刻滴答定时器的计数值 */
	int timer_cnt_per_ms = 0;           /* 1ms 时间对应的滴答定时器的计数值 */
	int timer_cnt_per_us = 0;           /* 1us 时间对应的滴答定时器的计数值 */

	/**
	 * 假设系统时钟是 84M
	 * 1s  时间, 滴答定时器计数值是 84,000,000
	 * 1ms 时间, 滴答定时器计数值是 84,000
	 * 1us 时间, 滴答定时器计数值是 84
	 */
	timer_cnt_per_ms = SystemCoreClock / (1000U / uwTickFreq);
	timer_cnt_per_us = timer_cnt_per_ms / 1000U;

	curr_systick_timer_val = SysTick->VAL;
	curr_systick_interrupt_cnt = HAL_GetTick();
	delay_us_timer_cnt = us * timer_cnt_per_us;

	if (delay_us_timer_cnt > curr_systick_timer_val) {
		while (HAL_GetTick() == curr_systick_interrupt_cnt) {
		}

		timeout_systick_timer_val = timer_cnt_per_ms + curr_systick_timer_val - delay_us_timer_cnt;

		while (timeout_systick_timer_val < SysTick->VAL) {
		}
	} else {
		timeout_systick_timer_val = curr_systick_timer_val - delay_us_timer_cnt;
		while (timeout_systick_timer_val < SysTick->VAL && HAL_GetTick() == curr_systick_interrupt_cnt) {
		}
	}
}

void delay_ms(int ms)
{
	HAL_Delay(ms);
}

void board_init()
{
	/* STM32 HAL LIB */
	HAL_Init();

	/* SYSTEM CLK */
	_board_clock_init();

	/* External crystal oscillator: PH0 PH1 */
	__HAL_RCC_GPIOH_CLK_ENABLE();

	/* SWD Download: PA13 PA14 */
	__HAL_RCC_GPIOA_CLK_ENABLE();

	_board_uart_init();
	_board_swi2c_init();
}
